#include "PostOffice.h"
#include "AbpaFileFormat.h"
#include "EofEvent.h"

namespace events {

/*static*/ PostOffice * PostOffice::_instance = NULL;
/*static*/ boost::once_flag PostOffice::_instance_flag;
/*
///static boost::mutex PostOffice::_inst_mutex;
	CRITICAL_SECTION PostOffice::_cs;

	PostOffice::all_events PostOffice::_events;


	struct CSInitializer {
		CSInitializer(CRITICAL_SECTION *cs) { ::InitializeCriticalSection(cs); }
	};
	CSInitializer doi(&PostOffice::_cs);
*/

/**
 * Writes standard ABPA file header
 */
void PostOffice::writeFileHeader(std::ostream &os, DWORD startTime) {
	events::AbpaFileFormat(startTime).saveAbpaHeader(os);
}


/*
 * Starts events' logger (in newly created thread)
 */
void PostOffice::startLoggerInThisThread(std::ostream &os, DWORD startTime) {
	_stopped = false;

	// initializes handler for "orphan" events - the ones
	// that belong to a thread being terminated, and was not processed
	// yet
	thread_events::OrphanElementsHandler handler;
	_events.for_each<OrphanEventsRegistry&>(OrphanEventsRegistry(&handler));

	// writes the standard header
	writeFileHeader(os, startTime);
	
	MultilistWaiter waiter;
	EventsWriter writer(os);
	while (!_stopped) {
		// waits until there are enough events in one of the
		// queues, or timeout of 500msec ends
		_events.for_each<MultilistWaiter&>(waiter);
		waiter.wait(500, _condStop.getWaitHandle());
		waiter.reset();

		// flushes events to the output file
		_events.for_each<EventsWriter&>(writer);
	}

	// no more events are expected
	_events.for_each<OrphanEventsRegistry&>(OrphanEventsRegistry(NULL));

	// collect remaining events
	OrphanEventsCollector collector(&handler);
	_events.for_each<OrphanEventsCollector&>(collector);
	unsigned long num_events = writer.getNumOfEvents();
	for (thread_events::OrphanElementsHandler::iterator it = handler.begin(); it != handler.end(); ++it) {
		BasicEvent *be = *it;
		os << (*be);
		num_events++;
		delete be;
	}

	// finalize the file
	EofEvent eEof(num_events);
	os << static_cast<BasicEvent&>(eEof);

	_condStopDone.set();
}


/*static*/ void PostOffice::ThreadExits(thread_events *list) {
	HANDLE h = list->stealWaitEvent();
	delete list;
	GetInstance()._condStop.set();
	if (h != NULL)
		::CloseHandle(h);
}



}  // end namespace
